﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace Agro.Library {
    public class JqGridExportExcelResult<T> : JqGridExportExcelResult
       where T : class {
        public JqGridExportExcelResult(IList<T> dataList)
            : base(ListToDataTable(dataList)) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="fileName">文件名</param>
        public JqGridExportExcelResult(IList<T> dataList, string fileName)
            : base(ListToDataTable(dataList), fileName) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="fileName">文件名</param>
        /// <param name="colModelOptionList">Jqgrid列配置信息</param>
        public JqGridExportExcelResult(IList<T> dataList, string fileName, List<ColModelOption> colModelOptionList)
            : base(ListToDataTable(dataList), fileName, colModelOptionList) { }

        #region ListToDataTable 反射处理，如果数据量不大，性能可以接受
        private static DataTable ListToDataTable(IList<T> dataList) {
            DataTable dtResult = new DataTable();
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            for (int i = 0; i < propertyInfos.Length; i++) {
                dtResult.Columns.Add(propertyInfos[i].Name, propertyInfos[i].PropertyType);
            }
            DataRow dr;
            foreach (var item in dataList) {
                dr = dtResult.NewRow();
                foreach (var propertyInfo in propertyInfos) {
                    dr[propertyInfo.Name] = item.GetType().GetProperty(propertyInfo.Name).GetValue(item, null);
                }
                dtResult.Rows.Add(dr);
            }
            return dtResult;
        }
        #endregion
    }

    /// <summary>
    /// JqGrid导出为Excel
    /// </summary>
    public class JqGridExportExcelResult : ActionResult {
        DataTable _dataTable = null;
        string _fileName = "";//文件名
        const string _fileExt = ".xls";//后缀
        //列配置
        List<ColModelOption> _colModelOptionList = null;

        #region 构造函数...
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dataTable"></param>
        public JqGridExportExcelResult(DataTable dataTable)
            : this(dataTable, DateTime.Now.ToFileTime() + _fileExt) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataTable"></param>
        /// <param name="fileName">文件名，不是完整路径，不带后缀</param>
        public JqGridExportExcelResult(DataTable dataTable, string fileName)
            : this(dataTable, fileName, null) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataTable">数据源</param>
        /// <param name="colModelOptionList">指定列配置信息</param>
        public JqGridExportExcelResult(DataTable dataTable, List<ColModelOption> colModelOptionList)
            : this(dataTable, DateTime.Now.ToFileTime() + _fileExt, colModelOptionList) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataTable">数据源</param>
        /// <param name="fileName"></param>
        /// <param name="colModelOptionList">指定列配置信息</param>
        public JqGridExportExcelResult(DataTable dataTable, string fileName, List<ColModelOption> colModelOptionList) {
            _dataTable = dataTable;
            _fileName = fileName;
            _colModelOptionList = colModelOptionList;
        }
        #endregion

        public override void ExecuteResult(ControllerContext context) {
            if (_colModelOptionList == null)//如果不指定，默认从Request里读取
            {
                string colModel = context.HttpContext.Request["colModel"];
                if (!string.IsNullOrEmpty(colModel)) {
                    JavaScriptSerializer js = new JavaScriptSerializer();
                    _colModelOptionList = (List<ColModelOption>)js.Deserialize(colModel, typeof(List<ColModelOption>));
                }
            }
            if (_colModelOptionList == null || _colModelOptionList.Count == 0)
                throw new ArgumentNullException("找不到Jgrid的列配置信息");
            _colModelOptionList = _colModelOptionList.FindAll(m => !m.hidden && _dataTable.Columns.Contains(m.name)).ToList();

            DataTable dtResult = _dataTable.Clone();
            for (int i = 0; i < dtResult.Columns.Count; i++) {
                dtResult.Columns[i].DataType = typeof(string);
            }

            for (int i = 0; i < _dataTable.Rows.Count; i++) {
                dtResult.ImportRow(_dataTable.Rows[i]);
            }



            for (int i = dtResult.Columns.Count - 1; i >= 0; i--) {
                ColModelOption option = _colModelOptionList.FirstOrDefault(m => m.name.Equals(dtResult.Columns[i].ColumnName));
                if (option == null)
                    dtResult.Columns.RemoveAt(i);//移除配置里不存在的列
                else {
                    dtResult.Columns[i].ColumnName = option.label;//列改DataTable列名为配置中的中文名
                    CovertRowValue(dtResult, i, option);
                }
            }
            //交换列顺序，以实现和Jqgrid的顺序一样
            Dictionary<string, int> columnIndexDic = new Dictionary<string, int>();
            Dictionary<int, int> columnWidthDic = new Dictionary<int, int>();//存储列宽设置
            for (int i = 0; i < dtResult.Columns.Count; i++) {
                ColModelOption option = _colModelOptionList.FirstOrDefault(m => !string.IsNullOrEmpty(m.label) && m.label.Equals(dtResult.Columns[i].ColumnName));
                int newIndex = _colModelOptionList.FindIndex(m => !string.IsNullOrEmpty(m.label) && m.label.Equals(option.label));
                columnIndexDic.Add(dtResult.Columns[i].ColumnName, newIndex);
                columnWidthDic.Add(newIndex, Convert.ToInt32(option.width * 0.15));//设置大致的列宽
            }
            //调整列顺序
            foreach (var item in columnIndexDic.OrderBy(m => m.Value))
                dtResult.Columns[item.Key].SetOrdinal(item.Value);

            //TODO:注： Ajax方式 如果指定文件名会存在重名隐患，暂未处理

            //由于Ajax方式不能处理文件下载，所以需要选把数据保存到文件，然后再以url形式下载该文件
            if (context.HttpContext.Request.IsAjaxRequest()) {
                //TODO: 此处暂时以硬编码的形式存放文件
                string relativePath = "/Files/Export/" + _fileName;
                string savePath = context.HttpContext.Server.MapPath("~/Files/Export/") + _fileName;
                NPOIHelper.WriteExcelToFile(dtResult, savePath, columnWidthDic.OrderBy(m => m.Key).Select(m => m.Value).ToArray());

                //把生成的文件路径传到前台
                new SNJsonResult(relativePath, string.Empty).ExecuteResult(context);
            }
            else
                new ExcelResult(dtResult, _fileName, columnWidthDic.OrderBy(m => m.Key).Select(m => m.Value).ToArray()).ExecuteResult(context);
        }

        #region CovertRowValue...
        static void CovertRowValue(DataTable dtSource, int columnIndex, ColModelOption option) {
            if (option == null || string.IsNullOrEmpty(option.formatter)) return;
            if (option.formatter.Equals("YNFmatter"))//格式为 是/否 的列
            {
                foreach (DataRow row in dtSource.Rows) {
                    if (row[columnIndex] != DBNull.Value)
                        row[columnIndex] = Convert.ToString(row[columnIndex]).Equals("1") ? "是" : "否";
                }
            }
            else if (option.formatter.Equals("select"))//处理formatter 为select的数据
            {
                Dictionary<string, string> valueDic = new Dictionary<string, string>();
                foreach (var item in option.editoptions.value.Split(';')) {
                    valueDic.Add(item.Split(':')[0], item.Split(':')[1]);
                }
                string rowValue = string.Empty;
                foreach (DataRow row in dtSource.Rows) {
                    if (row[columnIndex] != DBNull.Value) {
                        valueDic.TryGetValue(Convert.ToString(row[columnIndex]), out rowValue);
                        row[columnIndex] = rowValue;
                    }
                }
            }
        }
        #endregion
    }
}
